package ru.papergames.view.mediators
{
	import caurina.transitions.properties.FilterShortcuts;
	import flash.events.ContextMenuEvent;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.external.ExternalInterface;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.net.LocalConnection;
	import flash.system.System;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;
	import flash.utils.Timer;
	import mx.controls.Alert;
	import mx.core.UIComponent;
	import mx.managers.CursorManager;
	import mx.managers.SystemManagerGlobals;
	import org.puremvc.as3.interfaces.INotification;
	import ru.papergames.controller.notifications.CoreNotifications;
	import ru.papergames.controller.notifications.FrontendNotifications;
	import ru.papergames.model.binsocket.packets.response.*;
	import ru.papergames.model.proxies.HTTPProxy;
	import ru.papergames.model.proxies.MainHTTPProxy;
	import ru.papergames.model.proxies.MessagingSocketProxy;
	import ru.papergames.model.proxies.RegistrationProxy;
	import ru.papergames.model.proxies.SessionDataProxy;
	import ru.papergames.model.proxies.SettingsProxy;
	import ru.papergames.model.vo.PopupMessageVO;
	import ru.papergames.utils.constants.TopViews;
	import ru.papergames.utils.helpers.KeyboardHelper;
	import ru.papergames.view.mediators.BaseMediator;
	
	
	
		

	public class MainApplicationMediator extends BaseMediator
	{
		
		public static const NAME:String = 'MainApplicationMediator';
						
		private var _currentPopup:UIComponent;
		private var _popupCloseTOut:Number;
		private var _soundTransform:SoundTransform;
		
		private var _pendingPopupMessage:PopupMessageVO;
				
		private var _gcTimer:Timer = new Timer(30000, 0);
		
		public function MainApplicationMediator(viewComponent:Object=null)
		{
			super(NAME, viewComponent);
		}
		
		public function get currentTopView():String {
			return mainApp.currentState;
		}
		
		public function get mainApp():Main {
			return this.viewComponent as Main;
		}
				
		override public function onRegister():void {
			super.onRegister();
			
			FilterShortcuts.init();
			
			if (ExternalInterface.available) {
				var rootURL:String = ExternalInterface.call("document.location.toString");
				rootURL = rootURL.replace(/\/[^\/]+$/g, '/');
				
				SystemManagerGlobals.bootstrapLoaderInfoURL = rootURL;
				this.settingsProxy.rootURL = rootURL;
				
				logger.info("rootURL: " + rootURL);
			};
			
			_soundTransform = new SoundTransform(0);
			SoundMixer.soundTransform = _soundTransform;
			
			initStatCounters();
			
			initContextMenu();
			addListeners();
			getHttpSession();
			
			_gcTimer.start();
		}
		
		override public function onRemove():void {
			super.onRemove();
			
			removeListeners();
			makeGC();
			
			removeStatCounters();
			
			_gcTimer.stop();
			
			_gcTimer = null;
		}
		
		override public function listNotificationInterests():Array {
			var notes:Array = super.listNotificationInterests();
			
			notes.push(CoreNotifications.SYS_ERROR,
					   CoreNotifications.SYS_SERVER_EXCEPTION,
					   CoreNotifications.SYS_WARNING,
					   CoreNotifications.SYS_MESSAGE,
					   CoreNotifications.POPUP_MESSAGE,
					   
					   FrontendNotifications.OPEN_POPUP,
					   FrontendNotifications.SWITCH_TOP_VIEW,
					   FrontendNotifications.SWITCH_SOUND_STATE,
					   
					   RegistrationProxy.TRY_REGISTER_SUCCESS,
					   
					   HTTPProxy.START,
					   HTTPProxy.COMPLETE,
					   HTTPProxy.SERVICE_ERROR,
					   
					   SettingsProxy.SETTINGS_LOAD_ERROR,
					   MessagingSocketProxy.CONNECTION_ERROR,
					   
					   FrontendNotifications.GO_TO_REGISTRATION,
					   FrontendNotifications.CANCEL_REGISTRATION,
					   
					   FrontendNotifications.LOGOUT,
					   FrontendNotifications.SERVER_RESTARTING);
			
			return notes;
		}
		
		override public function handleNotification(note:INotification):void {
			
			var popupMsg:PopupMessageVO;
			
			switch(note.getName()) {
				case HTTPProxy.START:
					//show busy (not for ping!)
					var currMethod:String = note.getBody() as String;
					if (currMethod != SessionDataProxy.PING) 
						CursorManager.setBusyCursor();
					break;
					
				case HTTPProxy.COMPLETE:
					//hide busy (not for ping!)
					var currSuccessNote:String = note.getBody() as String;
					if (currMethod != SessionDataProxy.PING_SUCCESS)
						CursorManager.removeBusyCursor();
					break;
					
				
				case HTTPProxy.SERVICE_ERROR:
					
					if (settingsProxy.isDev)					
						facade.sendNotification(CoreNotifications.POPUP_MESSAGE, 
								new PopupMessageVO(note.getBody() as String, 'Ошибка сервера', false));
					
					CursorManager.removeAllCursors();
					
					break;
					
				case FrontendNotifications.OPEN_POPUP:
					
					break;				
				
				case CoreNotifications.SYS_ERROR:
					
					popupMsg = note.getBody() as PopupMessageVO;
					
					if (settingsProxy.isDev) 
						facade.sendNotification(CoreNotifications.POPUP_MESSAGE, popupMsg);
						logger.error("System Error: \n" + popupMsg.text);
					break;
					
				case CoreNotifications.SYS_SERVER_EXCEPTION:
					popupMsg = note.getBody() as PopupMessageVO;
					facade.sendNotification(CoreNotifications.POPUP_MESSAGE, popupMsg);
					logger.error("System Exception: \n" + popupMsg.text);
					break;
					
				case CoreNotifications.SYS_WARNING:
					popupMsg = note.getBody() as PopupMessageVO;
					facade.sendNotification(CoreNotifications.POPUP_MESSAGE, popupMsg);
					logger.warn("System Warning: \n" + popupMsg.text);
					break;
					
				case CoreNotifications.SYS_MESSAGE:
					popupMsg = note.getBody() as PopupMessageVO;
					facade.sendNotification(CoreNotifications.POPUP_MESSAGE, popupMsg);
					logger.info("System Info: \n" + popupMsg.text);
					break;
					
				case CoreNotifications.POPUP_MESSAGE:
					var pmvo:PopupMessageVO = note.getBody() as PopupMessageVO;
					
					Alert.show(pmvo.text, pmvo.title, Alert.OK, null, pmvo.closeFunction);
					
					break;
					
				case SettingsProxy.SETTINGS_LOAD_ERROR:
					facade.sendNotification(
								CoreNotifications.POPUP_MESSAGE, 
								new PopupMessageVO(
										'Произошла ошибка при загрузке файла конфигурации', 
										'Ошибка'
										)
								);
					break;
					
				case MessagingSocketProxy.CONNECTION_ERROR:
					facade.sendNotification(
								CoreNotifications.POPUP_MESSAGE, 
								new PopupMessageVO(
									'Произошла ошибка при конекте к мессаджинг-серверу: ' + String( note.getBody() ), 
									'Ошибка'
									)
								);
					break;
					
				case FrontendNotifications.SWITCH_TOP_VIEW:
					var topView:String = note.getBody() as String; 
					mainApp.currentState = topView;
									
					break;
					
				case FrontendNotifications.SWITCH_SOUND_STATE:
					_soundTransform.volume = Boolean(note.getBody()) ? 1 : 0;	
					//_soundTransform = new SoundTransform(0);
					SoundMixer.soundTransform = _soundTransform;				
					break;
					
				case FrontendNotifications.GO_TO_REGISTRATION:
					facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, TopViews.REGISTRATION); 
					break;
					
				case RegistrationProxy.TRY_REGISTER_SUCCESS:
				case FrontendNotifications.CANCEL_REGISTRATION:
					facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, TopViews.LOGIN); 
					break;
					
				case FrontendNotifications.LOGOUT:
					facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, TopViews.LOGIN);  
					break;
					
				case FrontendNotifications.SERVER_RESTARTING:					
					
					break;
						
				case SessionDataProxy.GET_SESSION_DATA_SUCCESS:					
					if ( !checkEntryPage() ) {
						facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, 
							loginProxy.loginVO.needPersCreation ? TopViews.PERS_CREATION : TopViews.GAME_UI); 
					}						
										
					break;
					
				case SessionDataProxy.GET_SESSION_DATA_FAULT:					 
					if ( !checkEntryPage() ) {
						facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, TopViews.LOGIN); 
					}
					break;
				
				case MessageFromWebServerResponse.NOTIFICATION:
					var mfwsr:MessageFromWebServerResponse = note.getBody() as MessageFromWebServerResponse;
					if (mfwsr.isSystemXML) handleSystemPacket( XML(mfwsr.message) );
					break;
					
				
				
			}
			
		}
		
		
		/*** PRIVATE IMPLEMENTATION ********/
		
		private function handleSystemPacket(data:XML):void {			
			MainHTTPProxy.mainResult(data);			
		}
		
		private function initStatCounters():void {
			//add stat data counter in right-top corner (memory + etc)
			//add in top most area
		}
		
		private function removeStatCounters():void {
			
			
		}
		
		private function initContextMenu():void {
			var newMenu:ContextMenu = new ContextMenu();
			
			newMenu.hideBuiltInItems();
			//
			//
			//newMenu.customItems.push(new ContextMenuItem(LocaleManager.getString(LocaleKey.APP_NAME), true, false));
			newMenu.customItems.push(new ContextMenuItem('PaperGames', true, false));
			//newMenu.customItems.push(new ContextMenuItem('.:: ver ' + LocaleManager.getVersion() + ' ::.', true, false));
			
			var sw_item:ContextMenuItem = new ContextMenuItem('MVC Console', true);	
			sw_item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onRightMenuSysLog);
			newMenu.customItems.push(sw_item);
				
			mainApp.contextMenu = newMenu;
		}
		
		private function onRightMenuSysLog(event:ContextMenuEvent):void {
			mainApp.mvcConsole.showPopup();
		}
		
		private function onRightMenuFight(event:ContextMenuEvent):void {	
			facade.sendNotification(FrontendNotifications.SWITCH_TOP_VIEW, TopViews.FIGHT); 
		}
				
		private function addListeners():void {			
			_gcTimer.addEventListener(TimerEvent.TIMER, makeGC);
			mainApp.systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_UP, KeyboardHelper.handleKeyBoardEvent, true, Number.MAX_VALUE, true);
			mainApp.systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_DOWN, KeyboardHelper.handleKeyBoardEvent, true, Number.MAX_VALUE, true);			
		}
		
		private function removeListeners():void {			
			_gcTimer.removeEventListener(TimerEvent.TIMER, makeGC);	
			mainApp.systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_UP, KeyboardHelper.handleKeyBoardEvent, true);
			mainApp.systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_DOWN, KeyboardHelper.handleKeyBoardEvent, true, Number.MAX_VALUE, true);			
		}
		
		private function getHttpSession():void {
			if (!ExternalInterface.available) return;
			
			var cookies:String = ExternalInterface.call("document.cookie.toString");
			
			//JSESSIONID=D28950F541471F6AD17BD720F47085F9; ...
			
			var session:String = '';
			
			try {
			
				var matches:Array = cookies.match(/JSESSIONID=([a-zA-Z0-9]{32})/i);
				
				if (matches && matches.length > 1) {
					session = matches[1];
					logger.debug('JSESSIONID: ' + session);	
				} else {
					logger.warn('No JSESSIONID found in cookies');				
				}
			
			} catch (e:Error) {
				logger.error('getHttpSession(): ' + e.message);
			}
			
			this.settingsProxy.httpSession = session;
		}
		
		private function checkEntryPage():Boolean {
			logger.info('Invoking checkEntryPage()');
			
			if (!ExternalInterface.available) return false;
			
			var location:String = ExternalInterface.call("document.location.toString");
			
			logger.debug('location: ' + location);	
			
			var parts:Array = location.split('#', 2);
			
			if (parts.length == 2) {
				var subPage:String = parts[1];
				
				if (subPage == 'registration') {
					facade.sendNotification(FrontendNotifications.GO_TO_REGISTRATION); 
					return true;
				}
			}
			
			return false;
		}
		
		protected function makeGC(evt:Event = null):void {
			logger.debug('Memory use: ' + System.totalMemory / (1024*1024) + ' MB');	
			logger.debug('Invoking GC...');						
			gcHack();
		}
		
		private function gcHack():void
		{		
	       // unsupported hack that seems to force a full GC		
	       try		
	       {		
	              var lc1:LocalConnection = new LocalConnection();		
	              var lc2:LocalConnection = new LocalConnection();		
	
	              lc1.connect('name');		
	              lc2.connect('name');		
	       }
	
	       catch (e:Error)		
	       {		
	       }		
		}
		
	}
}